package com.initapp.webapis.pownce
{
	import com.adobe.net.DynamicURLLoader;
	import com.adobe.webapis.URLLoaderBase;
	import com.dynamicflash.util.Base64;
	import com.initapp.webapis.pownce.events.PownceResultEvent;
	import com.initapp.webapis.pownce.results.PownceAuthResult;
	import com.initapp.webapis.pownce.results.PownceNotesResult;
	import com.initapp.webapis.pownce.results.PownceSendOptionsResult;
	import com.initapp.webapis.pownce.results.PownceUsersResult;
	
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.net.FileReference;
	import flash.net.URLRequest;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	
	use namespace pownce_internal;
	
	[Event(name="onGetPublicNoteList", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onGetNoteList", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onGetNote", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onGetNoteRecipientsList", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onGetProfile", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onGetFriendsFansFanOf", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onGetSendToList", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onPostAMessage", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onPostALink", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onPostAnEvent", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onPostAFile", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	[Event(name="onPostAReply", type="com.initapp.webapis.pownce.events.PownceResultEvent")]					
	[Event(name="onVerifyAuth", type="com.initapp.webapis.pownce.events.PownceResultEvent")]
	
	/**
	 * The Class is an ActionScript 3 Library for use against the Pownce V2.0 API
	 * 
	 * 
	 * @langversion ActionScript 3.0
	 * @playerversion Flash 9
	 * 
	 * @author Steven Gemmen
	 * 
	 * @see http://initapp.com
	 * @see http://pownce.pbwiki.com/API%20Documentation2-0
	 * @see http://groups.google.com/group/pownceapi
	 */
	public class PownceService extends URLLoaderBase
	{
		private const END_POINT:String = "http://api.pownce.com/2.0/";
		
		private var _pownceResultEvent:PownceResultEvent;
		
		private var _apiKey:String;
		private var _username:String;
		private var _password:String;

		/**
		 * Constructor.
		 * 
		 * @param apiKey Application key provided by Pownce
		 * @param username Optionally you can pass in username if you want to use an auth user at construction
		 * @param password Optionally you can pass in the password for auth
		 * 
		 * @see http://pownce.com/api/apps/new/ 
		 */		
		public function PownceService(apiKey:String, username:String = "", password:String = ""):void
		{
			setAuth(username, password);
			_apiKey = apiKey;
		}
		
		/**
		 * Set the username and password to be used for authorization for this instance.
		 * 
		 * @param username Pownce username
		 * @param password Pownce password
		 * 
		 */		
		public function setAuth(username:String, password:String):void{
			_username = username;
			_password = password;
		}
		/**
		 * Check that authentication is successful. This endpoint can be used to either test if the Http Basic auth header is correct.
		 * 
		 * @param noteType Filter the public notes by type. Options are messages, links, or events. Use NoteType
		 * @param limit Limit the number of notes returned. Default is 20 and max is 100.
		 * @param page Page number.
		 * @param sinceID Limit the notes returned to those greater than the specified note id.
		 * 
		 */	
		 public function verifyAuth(username:String, password:String):void{			
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			
			setAuth(username, password);
			urlRequest = getURLRequest("auth/verify.xml", URLRequestMethod.GET);
			
			urlLoader.addEventListener(Event.COMPLETE, onVerifyAuth);
			urlLoader.load(urlRequest);				
		}
		private function onVerifyAuth(event:Event):void{
			var pownceResult:PownceAuthResult = PownceResultParser.parseAuth(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_VERIFY_AUTH);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);				
		}
		/**
		 * Get a list of all recent public notes.
		 * 
		 * @param noteType Filter the public notes by type. Options are messages, links, or events. Use NoteType
		 * @param limit Limit the number of notes returned. Default is 20 and max is 100.
		 * @param page Page number.
		 * @param sinceID Limit the notes returned to those greater than the specified note id.
		 * 
		 */				
		public function getPublicNoteList(noteType:String = null, limit:int = 20, page:int = -1, sinceID:int = -1):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.limit = limit;
			
			noteType != null ? urlVariables.type = noteType + "s" : "";
			page != -1 ? urlVariables.page = page : "";
			sinceID != -1 ? urlVariables.since_id = sinceID : "";
			
			urlRequest = getURLRequest("note_lists.xml", URLRequestMethod.GET, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetPublicNoteList);
			urlLoader.load(urlRequest);
		}
		private function onGetPublicNoteList(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNotes(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_PUBLIC_NOTE_LIST);
			_pownceResultEvent.data = pownceResult;
			
			trace(event);
			dispatchEvent(_pownceResultEvent);
		}
		
		/**
		 * Get a list of notes for a user.
		 * 
		 * @param noteType Filter the public notes by type. Options are messages, links, or events. Use NoteType
		 * @param limit Limit the number of notes returned. Default is 20 and max is 100.
		 * @param page Page number.
		 * @param sinceID Limit the notes returned to those greater than the specified note id.
		 * @param noteSubsetType Get a subset of the authenticated user's note list. Options are notes (no replies), 
		 * replies, sent, public, private, nonpublic (private and friends-only notes), and all. If no filter is specified, 
		 * the notes will be returned according to the user's preferences.
		 * @param setID Filter the authenticated user's notes by a particular set. Only available for the authenticated user's own notes.
		 */	
		public function getNoteList(username:String, noteType:String = null, limit:int = 20, page:int = -1, sinceID:int = -1, noteSubsetType:String = null, setID:int = -1):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.limit = limit;
			
			noteType != null ? urlVariables.type = noteType + "s" : "";
			page != -1 ? urlVariables.page = page : "";
			sinceID != -1 ? urlVariables.since_id = sinceID : "";
			
			// Optional parameters for only authenticated users - use setAuth or pass auth in the constructor
			noteSubsetType != null ? urlVariables.filter = noteSubsetType : "";
			setID != -1 ? urlVariables.set_id = setID : "";
			
			urlRequest = getURLRequest("note_lists/" + username + ".xml", URLRequestMethod.GET, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetNoteList);
			urlLoader.load(urlRequest);			
		}
		private function onGetNoteList(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNotes(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_NOTE_LIST);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);			
		}
		
		/**
		 * Get a particular note by id.
		 * 
		 * @param noteID ID of the desired note.
		 * @param showNoteReplies Optional. By default the replies will not be included. To get the note with replies, use show_replies=true. Options are true or false.
		 * @param recipientLimit Optional. Number or recipients listed. Default is 0 and max is 100.
		 */	
		public function getNote(noteID:int, showNoteReplies:Boolean = false, recipientLimit:Number = 0):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.show_replies = showNoteReplies;
			urlVariables.recipient_limit = recipientLimit;
			
			urlRequest = getURLRequest("notes/" + String(noteID) + ".xml", URLRequestMethod.GET, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetNote);
			urlLoader.load(urlRequest);			
		}
		private function onGetNote(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNote(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_NOTE);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);			
		}

		/**
		 * Get a list of recipients for a particular note.
		 * 
		 * @param noteID ID of the desired note.
		 * @param limit Optional. Limit the number of recipients returned. Default is 20 and max is 100.
		 * @param Page Optional. Number or recipients listed. Default is 0 and max is 100.
		 */			
		public function getNoteRecipientList(noteID:int, limit:int = 20, page:Number = -1):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.note_id = noteID;
			
			urlVariables.limit = limit;
			page != -1 ? urlVariables.page = page : null;
			
			urlRequest = getURLRequest("notes/" + String(noteID) + "/recipients.xml", URLRequestMethod.GET, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetNoteRecipientList);
			urlLoader.load(urlRequest);				
		}
		private function onGetNoteRecipientList(event:Event):void{
			var pownceResult:PownceUsersResult = PownceResultParser.parseUserList(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_NOTE_RECIPIENT_LIST);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);				
		}

		/**
		 * Get an individual user's profile information.
		 * 
		 * @param username Username of a Pownce user.
		 */			
		public function getProfile(username:String):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.username = username;
			
			urlRequest = getURLRequest("users/" + username + ".xml", URLRequestMethod.GET, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetProfile);
			urlLoader.load(urlRequest);				
		}
		private function onGetProfile(event:Event):void{
			var pownceResult:PownceUsersResult = PownceResultParser.parseProfile(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_PROFILE);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);			
		}

		/**
		 * Get an individual user's relationship data.
		 * 
		 * @param username Username of a Pownce user.
		 * @param relationshipType Options are friends, fans, or fan_of. Use RelationshipType
		 * @param limit Optional. Limit the number of users returned. Default is 20 and max is 100.
		 * @param page Optional. Page number.
		 */			
		public function getFriendsFansAndFansOf(username:String, relationshipType:String, limit:int = 20, page:int = -1):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.username = username;
			
			urlVariables.limit = limit;
			page != -1 ? urlVariables.page = page : null;
			
			urlRequest = getURLRequest("users/" + username + "/" + relationshipType + ".xml", URLRequestMethod.GET, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetFriendFansAndFansOf);
			urlLoader.load(urlRequest);					
		}
		private function onGetFriendFansAndFansOf(event:Event):void{
			var pownceResult:PownceUsersResult = PownceResultParser.parseUserList(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_FRIENDS_FANS_FANOF);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);				
		}

		/**
		 * Get a the list of potential recipients for the authenticated user. Includes options for the public, all friends, sets, and individual friends.
		 * 
		 */			
		public function getSendToList():void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			
			urlRequest = getURLRequest("send/send_to.xml", URLRequestMethod.GET);
			
			urlLoader.addEventListener(Event.COMPLETE, onGetSendToList);
			urlLoader.load(urlRequest);				
		}
		private function onGetSendToList(event:Event):void{
			var pownceResult:PownceSendOptionsResult = PownceResultParser.parseSendToOptions(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_GET_SEND_TO_LIST);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);			
		}

		/**
		 * Post a note that contains only a message.
		 * 
		 * @param noteTo The recipient(s) of the note. Options are public, all, friend_x, or set_x. 
		 * Available options for the authenticated user can be found from the Send To List endpoint.
		 * @param noteBody The main text body of the note. 
		 */		
		public function postAMessage(noteTo:String, noteBody:String):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.note_to = noteTo;
			urlVariables.note_body = noteBody;
			
			urlRequest = getURLRequest("send/message.xml", URLRequestMethod.POST, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onPostAMessage);
			urlLoader.load(urlRequest);				
		}
		private function onPostAMessage(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNote(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_POST_A_MESSAGE);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);				
		}

		/**
		 * Post a note that contains a link.
		 * 
		 * @param noteTo The recipient(s) of the note. Options are public, all, friend_x, or set_x. Available options for the authenticated user can be found from the Send To List endpoint.
		 * @param The full url for the link. Ex: http://pythong.org
		 * @param Optional. The main text body of the note.
		 */			
		public function postALink(noteTo:String, url:String, noteBody:String = ""):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.note_to = noteTo;
			urlVariables.url = url;
			
			urlVariables.note_body = noteBody;
			
			urlRequest = getURLRequest("send/link.xml", URLRequestMethod.POST, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onPostALink);
			urlLoader.load(urlRequest);				
		}
		private function onPostALink(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNote(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_POST_A_LINK);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);			
		}

		/**
		 * Post a note that contains an event.
		 * 
		 * @param noteTo The recipient(s) of the note. Options are public, all, friend_x, or set_x. 
		 * Available options for the authenticated user can be found from the Send To List endpoint.
		 * @param eventName Name of the event.
		 * @param eventLocation Location of the event.
		 * @param eventDate Date of the event.
		 * @param noteBody Optional. The main text body of the note.
		 */		
		public function postAnEvent(noteTo:String, eventName:String, eventLocation:String, eventDate:Date, noteBody:String = ""):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.note_to = noteTo;
			urlVariables.event_name = eventName;
			urlVariables.event_location = eventLocation;
			urlVariables.event_date = PownceResultParser.parseDateForPownce(eventDate);
			
			urlVariables.note_body = noteBody;
			
			urlRequest = getURLRequest("send/event.xml", URLRequestMethod.POST, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onPostAnEvent);
			urlLoader.load(urlRequest);				
		}
		private function onPostAnEvent(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNote(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_POST_AN_EVENT);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);			
		}

		/**
		 * Post a note that contains a file.
		 * 
		 * @param noteTo The recipient(s) of the note. Options are all, friend_x, or set_x. 
		 * Available options for the authenticated user can be found from the Send To List endpoint.
		 * @param file The data of the file.
		 * @param noteBody Optional. The main text body of the note.
		 * @param usePro Must be set to true if the user posting the file has a pro account.
		 */		
		public function postAFile(noteTo:String, file:FileReference, noteBody:String = "", usePro:Boolean = false):void{
			var urlRequest:URLRequest;
			var urlVariables:URLVariables = new URLVariables();
			var url:String;
			
			url = usePro ? "send/file_pro.xml" : "send/file.xml";
			
			urlVariables.note_to = noteTo;
			urlVariables.note_body = noteBody;
			
			urlRequest = getURLRequest(url, URLRequestMethod.POST, urlVariables);
			
			file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, onPostAFile);
			file.upload(urlRequest, "media_file");				
		}
		private function onPostAFile(event:DataEvent):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNote(XML(event.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_POST_A_FILE);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);				
		}

		/**
		 * Post a reply to a note.
		 * 
		 * @param replyTo The id of the note which this reply belongs to.
		 * @param noteBody The main text body of the note.
		 * @param stars (messages, links, and files) The star rating the user gave the original note. 
		 * Options are 1, 2, 3, 4, or 5. Use NoteStarType.
		 * @param rsvp (events) The rsvp reply for an event type note. 
		 * Options are 1 Attending, 2 Busy Already, 3 Not Attending, 4 Running Late, 5 Bringing Friends, 6 Undecided, or 7 Wishing I Could Come!
		 * Use NoteRSVPType
		 */			
		public function postAReply(replyTo:int, noteBody:String = "", stars:int = -1, rsvp:int = -1):void{
			var urlRequest:URLRequest;
			var urlLoader:DynamicURLLoader = getURLLoader();
			var urlVariables:URLVariables = new URLVariables();
			
			urlVariables.reply_to = replyTo;
			
			// Optional
			urlVariables.note_body = noteBody;
			stars != -1 ? urlVariables.stars = stars : null;
			rsvp != -1 ? urlVariables.rsvp = rsvp : null;
			
			urlRequest = getURLRequest("send/reply.xml", URLRequestMethod.POST, urlVariables);
			
			urlLoader.addEventListener(Event.COMPLETE, onPostAReply);
			urlLoader.load(urlRequest);					
		}
		private function onPostAReply(event:Event):void{
			var pownceResult:PownceNotesResult = PownceResultParser.parseNote(XML(event.currentTarget.data));
			
			_pownceResultEvent = new PownceResultEvent(PownceResultEvent.ON_POST_A_REPLY);
			_pownceResultEvent.data = pownceResult;
			
			dispatchEvent(_pownceResultEvent);				
		}

		private function getURLRequest(url:String, method:String, urlVariables:URLVariables = null):URLRequest{
			// TODO: replace data with namevalue pair
			var urlRequest:URLRequest = new URLRequest();
			
			if(urlVariables == null){
				urlVariables = new URLVariables();
			}	
			
			switch(method){
				case "GET":
					urlVariables.app_key = _apiKey;
					urlRequest.url = END_POINT + url;
					urlRequest.method = URLRequestMethod.GET;
					break;
				case "POST":
					urlVariables.app_key = _apiKey;
					urlRequest.url = END_POINT + url;
					urlRequest.method = URLRequestMethod.POST;
					break;
			}
			
			urlRequest.data = urlVariables;

			if(_username != ""){
				var authHeader:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + Base64.encode(_username + ":" + _password));
	
				urlRequest.requestHeaders.push(authHeader);
			}
			
			return urlRequest;
		}		
		/*
		private static function base64Encode(data:String) : String
		{
		    var encoder:Base64Encoder = new Base64Encoder();
			var bytes:ByteArray = new ByteArray();
			bytes.writeUTFBytes(data);
		
		    encoder.encodeBytes(bytes);
		    return encoder.flush();
		}		*/
		
	}
}